home *** CD-ROM | disk | FTP | other *** search
/ Inter.Net 55-1 / Inter.Net 55-1.iso / CBuilder / Setup / BCB / data.z / utilcls.h < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-09  |  25.3 KB  |  1,089 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // UTILCLS.H - Utility Classes
  3. //
  4. // $Revision:   1.0.3.12  $
  5. // $Date:   03 Feb 1998 18:45:10  $
  6. //
  7. // Copyright (c) 1998 Borland International
  8. /////////////////////////////////////////////////////////////////////////////
  9. #ifndef __UTILCLS_H
  10. #define __UTILCLS_H
  11.  
  12. #include <objbase.h>
  13. #include <oleauto.h>
  14. #include <cguid.h>
  15. #include <stdarg.h>
  16. #include <tchar.h>
  17.  
  18. // Forward ref.
  19. //
  20. template <class DISPINTF = IDispatch>
  21. class TAutoDriver;
  22. template <class T>
  23. class TDebugHlpr;
  24.  
  25. // Macros
  26. //
  27.  
  28. // CONNECTIONPOINT_ARRAY_SIZE is used by the Fire_xxxx Event templates generated for
  29. // outgoing interfaces in the xxxx_TLB.H file.
  30. //
  31. #if !defined(CONNECTIONPOINT_ARRAY_SIZE)
  32. #define CONNECTIONPOINT_ARRAY_SIZE  5
  33. #endif
  34.  
  35. #if !defined(OLETEXT)
  36. #define OLETEXT(x)  L ## x
  37. #endif
  38.  
  39. #if !defined(OLETRACE)
  40. #define OLETRACE TDebugHlpr<TCHAR>::TRACE
  41. #endif
  42.  
  43. #if !defined(OLECHECK)
  44. #define OLECHECK(hrexpr) TDebugHlpr<TCHAR>::HRCHECK(hrexpr, #hrexpr, __FILE__, __LINE__)
  45. #endif
  46.  
  47. #if !defined(_ASSERTE)
  48. #define  _ASSERTE(expr) do {                                                            \
  49.   if (!(expr) && TDebugHlpr<TCHAR>::ASSERTE(#expr, __FILE__, __LINE__) == IDCANCEL)     \
  50.     ::DebugBreak();                                                                     \
  51. } while (0)
  52. #endif
  53.  
  54. // Version of _ASSERTE usable within inline functions
  55. // i.e. Does not have do/while construct which is not allowed in inline functions currently
  56. //
  57. #if !defined(_ASSERTE_)
  58. #define _ASSERTE_(expr)   ((expr) ? (0) : TDebugHlpr<TCHAR>::ASSERTE(#expr, __FILE__, __LINE__))
  59. #endif
  60.  
  61.  
  62. // TRACE/ASSERT/CHECK Helpers
  63. //
  64. template <class T>
  65. class TDebugHlpr
  66. {
  67. public:
  68.   static void __cdecl TRACE  (T* szFormat, ...);
  69.   static HRESULT      HRCHECK(HRESULT hr, const char *expr, const char* file = 0, int line = 0);
  70.   static int          ASSERTE(const char *expr, const char* file = 0, int line = 0);
  71.   static void         THROW  (const char *msg);
  72.   static int          PROMPT (const char *caption, const char *msg);
  73.  
  74.   // Determines whether we display a MsgBox. When 'false' we simply
  75.   // throw an exception.
  76.   //
  77.   static bool PromptOnAssertFailure;
  78.   static bool PromptOnHrCheckFailure;
  79. };
  80.  
  81.  
  82. // Governs how OLECHECK and _ASSERTE are handled - when false we refrain to display a 
  83. // MsgBox and simply throw an exception. If your code relies on try/catch to handle
  84. // these errors, you can disable prompting.
  85. //
  86. template <class T>
  87. bool TDebugHlpr<T>::PromptOnAssertFailure = false;
  88. template <class T>
  89. bool TDebugHlpr<T>::PromptOnHrCheckFailure= true;
  90.  
  91.  
  92. // Implementation of TRACE
  93. //
  94. template <class T>
  95. void __cdecl TDebugHlpr<T>::TRACE(T* szFormat, ...)
  96. {
  97.   va_list args;
  98.   va_start(args, szFormat);
  99.   int   bufSize;
  100.   TCHAR szBuffer[_MAX_PATH*2];
  101.   bufSize = wvsprintf(szBuffer, szFormat, args);
  102.   _ASSERTE(bufSize < sizeof(szBuffer));
  103.   ::OutputDebugString(szBuffer);
  104.   va_end(args);
  105. }
  106.  
  107. // OLECHECK - Throw an exception if !SUCCEEDED(hr)
  108. //
  109. template <class T>
  110. HRESULT __cdecl TDebugHlpr<T>::HRCHECK(HRESULT hr, const char* expr, const char* file, int line)
  111. {
  112.   if (!SUCCEEDED(hr))
  113.   {
  114. #if !defined(ClassesHPP)
  115.     static 
  116. #endif
  117.     TCHAR szMsg[_MAX_PATH*2];
  118.  
  119.     if (!file)
  120.       file = "";
  121.  
  122.     LPVOID msg = 0;
  123.     if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hr,
  124.                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), LPTSTR(&msg), 0, 0) && (msg != 0))
  125.     {
  126.       ::wsprintf(szMsg, "'%s': %s @ %s/%d", expr, LPTSTR(msg), file, line);
  127.       ::LocalFree(msg);
  128.     }
  129.     else
  130.       ::wsprintf(szMsg, _T("(%s) Error: %lX (%ld) @ %s/%d"), expr, LONG(hr), LONG(hr), file, line);
  131.  
  132.     int i = IDYES;
  133.     if (PromptOnHrCheckFailure)
  134.       i = PROMPT("HRESULT Failure", szMsg);
  135.     if (i == IDYES)
  136.       THROW(szMsg);
  137.     else if (i == IDCANCEL)
  138.       ::DebugBreak();
  139.     // NOTE: IDNO - implies we keep chugging along
  140.   }
  141.  
  142.   return hr;
  143. }
  144.  
  145. // _ASSERTE helper return MB_YES, MB_NO or MB_CANCEL
  146. //
  147. template <class T>
  148. int TDebugHlpr<T>::ASSERTE(const char* expr, const char* file, int line)
  149. {
  150. #if !defined(ClassesHPP)
  151.   static
  152. #endif
  153.   TCHAR msg[_MAX_PATH*2];
  154.   ::wsprintf(msg, "%s @ %s/%d", LPTSTR(expr), file, line);
  155.  
  156.   int i = IDYES;
  157.  
  158.   if (PromptOnAssertFailure)
  159.     i = PROMPT("Assertion Failure", msg);
  160.  
  161.   if (i == IDYES)
  162.   {
  163.     ::wsprintf(msg, "%s failed - %s/%d", expr, file, line);
  164.     THROW(msg);
  165.   }
  166.   return i;
  167. }
  168.  
  169. // Helper used to throw an exception
  170. //
  171. template <class T>
  172. void TDebugHlpr<T>::THROW(const char* msg)
  173. {
  174. // Use VCL class, if VCL headers have been seen
  175. //
  176. #if defined(ClassesHPP)
  177.   throw Exception(AnsiString(msg));
  178. #else
  179.   throw msg;
  180. #endif
  181. }
  182.  
  183. // Helper used to display a MessageBox
  184. //
  185. template <class T>
  186. int TDebugHlpr<T>::PROMPT(const char* caption, const char* msg)
  187. {
  188.   TCHAR szMsg[_MAX_PATH*2];
  189.   wsprintf(szMsg, "%s\nPress [Y]es to terminate, [N]o to continue and [C]ancel to Debug", msg);
  190.   return ::MessageBox(0, szMsg, caption, MB_TASKMODAL|MB_ICONQUESTION|MB_YESNOCANCEL);
  191. }
  192.  
  193.  
  194. // TPtrBase
  195. // Base class for automation pointer management. Provides basic implementation for
  196. // smart pointer object.
  197. //
  198. template<class T> 
  199. class TPtrBase
  200. {
  201. public:
  202.   // Methods implementing pointer semantics
  203.   //
  204.   T&  operator *  ()    const { _ASSERTE_(m_ptr); return *m_ptr; }
  205.       operator T* ()    const { return m_ptr;}
  206.       bool operator !() const { return m_ptr == 0; }
  207.   T*   operator->()    const  { _ASSERTE_(m_ptr); return m_ptr;  }
  208.   T**  operator &()/*const*/  { return &m_ptr; }      
  209.  
  210.   // Comparison operators
  211.   //
  212.   bool operator == (T                 *rhs) const { return m_ptr == rhs;}
  213.   bool operator == (const TPtrBase<T> &rhs) const { return m_ptr == rhs.m_ptr; }
  214.   bool operator != (T                 *rhs) const { return m_ptr != rhs;}
  215.   bool operator != (const TPtrBase<T> &rhs) const { return m_ptr != rhs.m_ptr; }
  216.  
  217. protected:
  218.    TPtrBase()     : m_ptr(0) {}
  219.    TPtrBase(T* p) : m_ptr(p) {}
  220.  
  221.    T* get        () const   { return m_ptr;    }
  222.    T* release    ()         { return reset(0); }
  223.    T* reset      (T* p = 0) { T* tmp = m_ptr; m_ptr = p; return tmp; }
  224.  
  225.    // Actual data
  226.    //
  227.    T* m_ptr;
  228.  
  229. private:
  230.     // Prevent new/delete
  231.     //
  232.     void* operator new(size_t);
  233.     void  operator delete(void *p){/*::delete p;*/};
  234. };
  235.  
  236.  
  237. // TPtr: Smart pointer object for non-array pointers
  238. //
  239. template<class T> 
  240. class TPtr : public TPtrBase<T>
  241. {
  242. public:
  243.   TPtr()             : TPtrBase<T>()              {}
  244.   TPtr(T*       src) : TPtrBase<T>(src)           {}
  245.   TPtr(TPtr<T>& src) : TPtrBase<T>(src.release()) {}
  246.  ~TPtr()                                          {clear(0);}
  247.  
  248.   // Assignment operators
  249.   //
  250.   TPtr& operator = (TPtr<T>& src) 
  251.   { 
  252.     // Transfer ownership of pointer to receiver
  253.     //
  254.     reset(src.release()); 
  255.     return *this; 
  256.   }
  257.   TPtr& operator = (T* src) 
  258.   { 
  259.     clear(src);
  260.     return *this;
  261.   }
  262.  
  263.   // Clear object - free pointer
  264.   //
  265.   void clear(T *src)
  266.   {
  267.     if (m_ptr)
  268.       delete m_ptr;
  269.     m_ptr = src;
  270.   }
  271. };
  272.  
  273.  
  274. // TAPtr: Smart pointer object for array new'ed memory
  275. //
  276. template<class T> 
  277. class TAPtr : public TPtrBase<T>
  278. {
  279. public:
  280.   TAPtr()             : TPtrBase<T>()              {}
  281.   TAPtr(T      src[]) : TPtrBase<T>(src)           {}
  282.   TAPtr(TPtr<T>& src) : TPtrBase<T>(src.release()) {}
  283.  ~TAPtr()                                          {clear(0);}
  284.  
  285.   // Assignment operators
  286.   //
  287.   TAPtr& operator = (TAPtr<T>& src) 
  288.   { 
  289.     // Transfer ownership of pointer to receiver
  290.     //
  291.     reset(src.release()); 
  292.     return *this; 
  293.   }
  294.   TAPtr& operator = (T src[]) 
  295.   { 
  296.     clear(src);
  297.     return *this;
  298.   }
  299.  
  300.   // Subscript operator (for array)
  301.   //
  302.   T& operator [](int i) const
  303.   {
  304.     _ASSERTE_(m_ptr);
  305.     return m_ptr[i];
  306.   }
  307.  
  308.   // Clear object - free pointer
  309.   //
  310.   void clear(T src[])
  311.   {
  312.     if (m_ptr)
  313.       delete []m_ptr;
  314.     m_ptr = src;
  315.   }
  316. };
  317.  
  318.  
  319. // TInitOle: Simple object to initialize and unintialize Ole in a safe fashion
  320. //
  321. class TInitOle 
  322. {
  323. public:
  324.   TInitOle()
  325.   {
  326.     init = SUCCEEDED(::CoInitialize(0));
  327.   }
  328.  ~TInitOle()
  329.   {
  330.     if (init)
  331.       ::CoUninitialize();
  332.   }
  333.  
  334.   // Methods to test whether initialization was succcessful
  335.   //
  336.   operator bool () const
  337.   {
  338.     return init;
  339.   }
  340.   int operator ! () const
  341.   {
  342.     return init == false;
  343.   }
  344.  
  345. protected:
  346.   // Flags if initialization was successful 
  347.   //
  348.   bool init;
  349.  
  350. private:
  351.   // Prevent accidental copy to ensure equal numbers of Init/UnInit
  352.   //
  353.   TInitOle(const TInitOle&);
  354.   TInitOle& operator = (const TInitOle&);
  355. };
  356.  
  357.  
  358. // Helper class used to create Default Interface Wrapper of CoClasses
  359. // (Used by Code generated by TLIBIMP)
  360. //
  361. class CoClassCreator
  362. {
  363. public:
  364.   // Enhanced version of CoCreateInstance that handles failure due to CLSCTX_REMOTESERVER Flag
  365.   //
  366.   static HRESULT CoCreateInstance(REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv)
  367.   {
  368.     HRESULT hr;
  369.  
  370.   // Define NO_REMOTE_BINDING if you do not want to try to bind to a remote server 
  371.   //
  372. #if !defined(NO_REMOTE_BINDING)
  373.     hr = ::CoCreateInstance(rclsid, 0, CLSCTX_SERVER, riid, ppv);
  374.  
  375.     // If succeeded, or failed for reasons other than invalid arguments
  376.     //
  377.     if (SUCCEEDED(hr)  || hr != E_INVALIDARG)
  378.       return hr;
  379. #endif
  380.  
  381.     // Call CoCreateInstance, this time masking off CLSCTX_REMOTE_SERVER
  382.     //
  383.     hr = ::CoCreateInstance(rclsid, 0, CLSCTX_SERVER & ~CLSCTX_REMOTE_SERVER, riid, ppv);
  384.     return hr;
  385.   }
  386. };
  387.  
  388.  
  389. // Generic COM Interface wrapper
  390. // Performs proper AddRef/Release when object is copied, assigned to and deleted
  391. //
  392. template <class T>
  393. class TComInterface
  394. {
  395. public:
  396.   TComInterface() : intf(0) 
  397.   {}
  398.  
  399.   // NOTE: The default behaviour of the constructor is not to AddRef the interface
  400.   //       pointer parameter. This is appropriate if the interface was obtained
  401.   //       has already been addRef'ed - as when retrieving a Font property.
  402.   //
  403.   TComInterface(T* p, bool addRef = false)
  404.   {
  405.     if (((intf = p) != 0) && addRef)
  406.       intf->AddRef();
  407.   }
  408.  
  409.   TComInterface(const TComInterface<T>& src)
  410.   {
  411.     if ((intf = src.intf) != 0)
  412.       intf->AddRef();
  413.   }
  414.  
  415.  ~TComInterface() 
  416.   {
  417.     Reset();
  418.   }
  419.  
  420.   operator T* () const
  421.   {
  422.     return intf;
  423.   }
  424.  
  425.   T& operator*() 
  426.   {
  427.     _ASSERTE_(intf!=0); 
  428.     return *intf; 
  429.   }
  430.  
  431.   // NOTE: You must explicitly Reset() any held interface pointers before invoking
  432.   //       the &operator (presumably to store another interface in the object)
  433.   //
  434.   T** operator & () 
  435.   { 
  436.     _ASSERTE_(intf==0); 
  437.     return &intf;
  438.   }
  439.  
  440.   T* operator->() const 
  441.   { 
  442.     _ASSERTE_(intf != 0); 
  443.     return intf; 
  444.   }
  445.  
  446.   T* operator->()
  447.   {
  448.     _ASSERTE_(intf != 0);
  449.     return intf;
  450.   }
  451.  
  452.   void Reset(T* p = 0) 
  453.   {
  454.     if (intf) 
  455.       intf->Release(); 
  456.     intf=p;
  457.   }
  458.  
  459.   void Bind(T* p, bool addRef = false)
  460.   {
  461.     if (p && addRef)
  462.       p->AddRef();
  463.     Reset(p);
  464.   }
  465.  
  466.   void Unbind()
  467.   {
  468.     Reset(0);
  469.   }
  470.  
  471.   // NOTE: The assignment operator does *NOT* addRef the interface pointer being 
  472.   //       assigned to this object.
  473.   //
  474.   TComInterface<T>& operator=(T* p)
  475.   {
  476.     Bind(p);
  477.     return *this;
  478.   }
  479.  
  480.   TComInterface<T>& operator=(const TComInterface<T>& src)
  481.   {
  482.     if (src.intf != 0)
  483.       src.intf->AddRef();
  484.     Reset(src.intf);
  485.   }
  486.  
  487.   bool operator ! () const
  488.   {
  489.     return (intf == 0);
  490.   }
  491.  
  492.  
  493.   bool IsBound() const
  494.   {
  495.     return !!(*this);
  496.   }
  497.  
  498. protected:
  499.   T* intf;
  500. };
  501.  
  502. // Typedefs for standard interfaces
  503. //
  504. typedef TComInterface<IUnknown>  TCOMIUnknown;
  505. typedef TComInterface<IDispatch> TCOMIDispatch;
  506.  
  507. // Just in case this class is used solely for helper objects and
  508. // not for Automation
  509. //
  510. #if !defined(UTILCLS_NO_AUTOMATION)
  511.  
  512. // Helper class for cases where VARIANT* or VARIANT& is expected for optional parameters
  513. //
  514. class TNoParam 
  515. {
  516. public:
  517.   TNoParam()
  518.   {
  519.     ::VariantInit(&m_Variant);
  520.     m_Variant.vt = VT_ERROR;
  521.     V_ERROR(&m_Variant) = DISP_E_PARAMNOTFOUND;
  522.   }
  523.  ~TNoParam()
  524.   {
  525.     ::VariantClear(&m_Variant);
  526.   }
  527.   operator VARIANT* () 
  528.   {
  529.     return &m_Variant;
  530.   }
  531.   operator VARIANT& () 
  532.   {
  533.     return m_Variant;
  534.   }
  535.   
  536. private:
  537.   VARIANT m_Variant;
  538. };
  539.  
  540.  
  541. // The following ensures that Automation Drivers are not tied to VCL's Variant
  542. // Any VARIANT wrapper which exposes ctr, assignment op, and conversion op. for
  543. // Automation compatible types will do.
  544. //
  545. #if !defined __VARIANTOBJ_DEFINED
  546. #define __VARIANTOBJ_DEFINED
  547. typedef System::Variant VARIANTOBJ;
  548. #endif
  549.  
  550. // Base class that exposes basic behaviour of our array of Variants
  551. //
  552. class TAutoArgsBase
  553. {
  554. protected:
  555.   TAutoArgsBase(VARIANTOBJ *pVariant, int count) : m_Variant(pVariant), m_Count(count)
  556.   {}
  557.  
  558. public:
  559.   VARIANTOBJ& operator[](int index) const
  560.   {
  561.     // NOTE: It's OK to use Count - there's an extra Variant for return result
  562.     //       Zero'th entry's reserved for return value.
  563.     //
  564.     _ASSERTE_(index <= m_Count);
  565.     _ASSERTE_(index >= 0);
  566.  
  567.     // Make up for C++ vs. Basic reverse indexing
  568.     //
  569.     return m_Variant[index ? (m_Count+1-index) : 0];
  570.   }
  571.  
  572.   VARIANT* GetRetVal() const
  573.   {
  574.     return (VARIANT*)(m_Variant);
  575.   }
  576.  
  577.   VARIANTOBJ& GetRetVariant()
  578.   {
  579.     return *m_Variant;
  580.   }
  581.  
  582.   VARIANT* GetArgs() const
  583.   {
  584.     return (VARIANT*)(m_Variant+1);
  585.   }
  586.  
  587.   int GetCount() const
  588.   {
  589.     return m_Count;
  590.   }
  591.  
  592. private:
  593.   TAutoArgsBase(const TAutoArgsBase&);
  594.   TAutoArgsBase& operator=(const TAutoArgsBase&);
  595.  
  596.   VARIANTOBJ *m_Variant;
  597.   int         m_Count;
  598. };
  599.  
  600.  
  601. // TAutoArgs - Encapsulates array of Variants. Use for Invoke calls
  602. //
  603. template <int Count>
  604. class TAutoArgs : public TAutoArgsBase
  605. {
  606. public:
  607.   TAutoArgs();
  608.  ~TAutoArgs();
  609.  
  610. private:
  611.   // Allocate an extra Variant. It's the first entry  and
  612.   // it is reserved for return result. The rest are for parameters
  613.   //
  614.   VARIANTOBJ m_Array[Count+1];
  615. };
  616.  
  617.  
  618. // Build an array of Count (actualy Count+1, extra one for return value)
  619. // of VARIANTs.
  620. //
  621. template <int Count>
  622. TAutoArgs<Count>::TAutoArgs() : TAutoArgsBase(m_Array, Count)
  623. {}
  624.  
  625.  
  626. // Cleanup array of Variants
  627. //
  628. template <int Count>
  629. TAutoArgs<Count>::~TAutoArgs()
  630. {}
  631.  
  632.  
  633. // Enumeration describing DISPATCH type
  634. //
  635. enum DispatchFlag
  636. {
  637.   dfMethod    = DISPATCH_METHOD,
  638.   dfPropGet   = DISPATCH_PROPERTYGET,
  639.   dfPropPut   = DISPATCH_PROPERTYPUT,
  640.   dfPropPutRef= DISPATCH_PROPERTYPUTREF
  641. };
  642.  
  643. // Sets the value in the returnVariant to the retVal variable if SUCCEEDED(hr)
  644. // Used by DispInterface Code Generated by TLIBIMP
  645. //
  646. template <class T>
  647. HRESULT OutRetValSetterPtr(T* retVal, TAutoArgsBase& args, HRESULT hr)
  648. {
  649.   if (SUCCEEDED(hr))
  650.     *retVal = args.GetRetVariant();
  651.   return hr;
  652. }
  653.  
  654. // Sets the value in the returnVariant to the retVal variable if SUCCEEDED(hr)
  655. // Used by DispInterface Code Generated by TLIBIMP
  656. template <class T>
  657. HRESULT OutRetValSetterRef(T& retVal, TAutoArgsBase& args, HRESULT hr)
  658. {
  659.   if (SUCCEEDED(hr))
  660.     retVal = args.GetRetVariant();
  661.   return hr;
  662. }
  663.  
  664.  
  665. // Base class of AutoDrivers - provides an optional parameter
  666. //
  667. template <class DISPINTF>
  668. class TAutoDriverBase
  669. {
  670. public:
  671.   static TNoParam OptParam;
  672. };
  673.  
  674. // Static/shared instance of 'Optional Parameters'
  675. //
  676. template <class T>
  677. TNoParam TAutoDriverBase<T>::OptParam;
  678.  
  679. // TAutoDriver - DispInterface Automation Proxy Driver
  680. //
  681. template <class DISPINTF>
  682. class TAutoDriver : public TAutoDriverBase<IDispatch>
  683. {
  684. public:
  685.   TAutoDriver(LCID lcid = LOCALE_SYSTEM_DEFAULT);
  686.   TAutoDriver(const TAutoDriver<DISPINTF>  &src);
  687.  ~TAutoDriver();
  688.  
  689.   // Bind via various mechanisms & Unbind
  690.   // NOTE: Does *NOT* AddRef interface
  691.   //
  692.   void    Bind(DISPINTF *pintf);
  693.   HRESULT Bind(LPUNKNOWN punk);
  694.   HRESULT Bind(const GUID& guid);
  695.   HRESULT Bind(LPCWSTR progid);
  696.  
  697.   // Bind to running copy of Server
  698.   //
  699.   HRESULT BindToActive(const GUID& guid);
  700.   HRESULT BindToActive(LPCWSTR propid);
  701.  
  702.   // Unbind from DispInterface
  703.   //
  704.   void    Unbind(bool release = true);
  705.  
  706.   // Assignment of interface to object implies Bind to interface
  707.   //
  708.   TAutoDriver<DISPINTF>& operator =(DISPINTF *pintf)
  709.   {
  710.     Bind(pintf);
  711.     return *this;
  712.   }
  713.  
  714.   // Return Dispatch Interface
  715.   //
  716.   operator DISPINTF*()  const;
  717.   bool     IsBound()    const;
  718.  
  719.   // Allows access to interface being held
  720.   // NOTE: Useful when dealing with dual interfaces 
  721.   //       Using '->' yields Vtable call while '.' yields Invoke call
  722.   DISPINTF* operator -> ()
  723.   {
  724.     return m_Dispatch;
  725.   }
  726.  
  727.   // Return address of interface
  728.   //
  729.   DISPINTF** operator & ()
  730.   {
  731.     // Can take address (to presumably stuff new interface pointer) only if
  732.     // not currently Bound;
  733.     _ASSERTE_(m_Dispatch==0);
  734.     return &m_Dispatch;
  735.   }
  736.  
  737.   // Wrappers of IDispatch methods
  738.   //
  739.   HRESULT GetIDsOfNames(LPCWSTR name, DISPID &id);
  740.   HRESULT Invoke(DispatchFlag dFlags, LPCWSTR name, TAutoArgsBase* args, bool hasRetVal = true);
  741.   HRESULT Invoke(DispatchFlag dFlags, DISPID dispId, TAutoArgsBase* args, bool hasRetVal = true);
  742.  
  743.   // Procedures with/without parameters
  744.   //
  745.   void OleProcedure(DISPID dispId, TAutoArgsBase& args)
  746.   {
  747.     Invoke(dfMethod, dispId, &args, false);
  748.   }
  749.   void OleProcedure(DISPID dispid)
  750.   {
  751.     Invoke(dfMethod, dispid, 0, false);
  752.   }
  753.  
  754.   // FUnctions with/without parameters
  755.   HRESULT OleFunction(DISPID dispid, TAutoArgsBase& args)
  756.   {
  757.     return Invoke(dfMethod, dispid, &args, true);
  758.   }
  759.   HRESULT OleFunction(DISPID dispid)
  760.   {
  761.     return Invoke(dfMethod, dispid, 0, false);
  762.   }
  763.  
  764.   // Property put (always has parameters)
  765.   HRESULT OlePropertyPut(DISPID dispid, TAutoArgsBase& args)
  766.   {
  767.     return Invoke(dfPropPut, dispid, &args, false);
  768.   }
  769.  
  770.   // Property get (always has parameters, even if just TAutoArgs<0>)
  771.   HRESULT OlePropertyGet(DISPID dispid, TAutoArgsBase& args)
  772.   {
  773.     return Invoke(dfPropGet, dispid, &args, true);
  774.   }
  775.  
  776.   // Property get that returns VARIANT
  777.   VARIANTOBJ OlePropertyGet(DISPID dispid);
  778.  
  779. protected:
  780.   DISPINTF   *m_Dispatch;           // Disp Interface Pointer
  781.   LCID        m_lcid;               // Locale for DispId lookup & Invoke
  782.   EXCEPINFO   m_ExcepInfo;          // Exception Structure
  783.   UINT        m_ErrArg;             // Index of erroneous argument
  784.   TInitOle    m_InitOle;            // Ensure OLE's Initialied
  785. };
  786.  
  787.  
  788. // Ctr & Dtr of Automation Driver class
  789. //
  790. template <class DISPINTF>
  791. TAutoDriver<DISPINTF>::TAutoDriver(LCID lcid) : m_Dispatch(0), m_lcid(lcid)
  792. {}
  793.  
  794. //
  795. template <class DISPINTF>
  796. TAutoDriver<DISPINTF>::TAutoDriver(const TAutoDriver<DISPINTF>  &src)
  797.   // NOTE: We do not copy the Exception, ErrArg or InitOle object
  798.   //       We simply clear them out
  799.   m_ErrArg = 0;
  800.   ::ZeroMemory(&m_ExcepInfo, sizeof(m_ExcepInfo));
  801.  
  802.   // Copy Interface and AddRefCount
  803.   m_Dispatch = src.m_Dispatch;
  804.   if (m_Dispatch)
  805.     m_Dispatch->AddRef();
  806.  
  807.   // Copy Locale
  808.   m_lcid = src.m_lcid;
  809. }
  810.  
  811. template <class DISPINTF>
  812. TAutoDriver<DISPINTF>::~TAutoDriver()
  813. {
  814.   Unbind();
  815. }
  816.  
  817. // Bind via Dispatch Interface
  818. // NOTE: Does *NOT* AddRef interface
  819. //
  820. template <class DISPINTF> void    
  821. TAutoDriver<DISPINTF>::Bind(DISPINTF *pintf)
  822. {
  823.   Unbind();
  824.   m_Dispatch = pintf;
  825. }
  826.  
  827. // Bind via IUnknown
  828. //
  829. template <class DISPINTF> HRESULT 
  830. TAutoDriver<DISPINTF>::Bind(LPUNKNOWN punk)
  831. {
  832.   _ASSERTE(punk);
  833.   HRESULT hr = E_POINTER;
  834.   if (punk)
  835.   {
  836.     DISPINTF *disp;
  837.     hr = punk->QueryInterface(IID_IDispatch, (LPVOID*)&disp);
  838.     if (SUCCEEDED(hr))
  839.       Bind(disp);
  840.   }
  841.   return hr;
  842. }
  843.  
  844. // Bind via GUID
  845. //
  846. template <class DISPINTF> HRESULT 
  847. TAutoDriver<DISPINTF>::Bind(const GUID& clsid)
  848. {
  849.   LPUNKNOWN punk = 0;
  850.   HRESULT hr = CoClassCreator::CoCreateInstance(clsid, IID_IUnknown, (LPVOID*)&punk);
  851.   if (SUCCEEDED(hr))
  852.   {
  853.     // We should have a valid interface pointer
  854.     //
  855.     _ASSERTE(punk);
  856.  
  857.     // Run Object - just in case
  858.     //
  859.     hr = ::OleRun(punk);
  860.     
  861.     // Bind to running IUnknown
  862.     //
  863.     if (SUCCEEDED(hr))
  864.       hr = Bind(punk);
  865.  
  866.     // Release IUnknown
  867.     //
  868.     punk->Release();
  869.   }
  870.   return hr;
  871. }
  872.  
  873. // Bind via ProgId
  874. //
  875. template <class DISPINTF> HRESULT 
  876. TAutoDriver<DISPINTF>::Bind(LPCWSTR progid)
  877. {
  878.   GUID clsid;
  879.   HRESULT hr = ::CLSIDFromProgID(progid, &clsid);
  880.   if (SUCCEEDED(hr))
  881.     return Bind(clsid);
  882.   return hr;
  883. }
  884.  
  885. // Bind to running copy of Object of this CLSID
  886. //
  887. template <class DISPINTF> HRESULT 
  888. TAutoDriver<DISPINTF>::BindToActive(const GUID& guid)
  889. {
  890.   LPUNKNOWN punk = 0;
  891.   HRESULT hr = ::GetActiveObject(guid, 0, &punk);
  892.   if (SUCCEEDED(hr))
  893.     return Bind(punk);
  894.   return hr;
  895. }
  896.  
  897. // Bind to running copy of object with the specified progId
  898. //
  899. template <class DISPINTF> HRESULT
  900. TAutoDriver<DISPINTF>::BindToActive(LPCWSTR progid)
  901. {
  902.   CLSID clsid;
  903.   HRESULT hr = ::CLSIDFromProgID(progid, &clsid);
  904.   if (SUCCEEDED(hr))
  905.     return BindToActive(clsid);
  906.   return hr;
  907. }
  908.  
  909. // Release Dispatch Interface
  910. //
  911. template <class DISPINTF> void  
  912. TAutoDriver<DISPINTF>::Unbind(bool release = true)
  913. {
  914.   if (release && m_Dispatch)
  915.     m_Dispatch->Release();
  916.   m_Dispatch = 0;
  917. }
  918.  
  919. // Return Dispatch Interface
  920. //
  921. template <class DISPINTF> 
  922. TAutoDriver<DISPINTF>::operator DISPINTF* () const
  923. {
  924.   return m_Dispatch;
  925. }
  926.  
  927. // Returns Boolean indicating whether we're currently bound to the Server
  928. //
  929. template <class DISPINTF> bool 
  930. TAutoDriver<DISPINTF>::IsBound() const
  931. {
  932.   return m_Dispatch != 0;
  933. }
  934.  
  935. // Encapsulation of IDispatch->GetIDsOfNames
  936. //
  937. template <class DISPINTF> HRESULT 
  938. TAutoDriver<DISPINTF>::GetIDsOfNames(LPCWSTR name, DISPID &id)
  939. {
  940.   _ASSERTE(name);
  941.   _ASSERTE(IsBound());
  942.   return m_Dispatch->GetIDsOfNames(IID_NULL, (LPWSTR*)(&name), 1, m_lcid, &id);
  943. }
  944.  
  945. // Invoke specified 'name'
  946. //
  947. template <class DISPINTF> HRESULT 
  948. TAutoDriver<DISPINTF>::Invoke(DispatchFlag dFlags, LPCWSTR name, TAutoArgsBase* args, bool hasRetVal = true)
  949. {
  950.   DISPID dispid;
  951.   HRESULT hr = GetIDsOfNames(name, dispId);
  952.   if (SUCCEEDED(hr))
  953.     hr = Invoke(dFlags, dispid, args);
  954.   return hr;
  955. }
  956.  
  957. // Invoke specified 'DispId'
  958. //
  959. template <class DISPINTF> HRESULT 
  960. TAutoDriver<DISPINTF>::Invoke(DispatchFlag dFlags, DISPID dispid, TAutoArgsBase* args, bool hasRetVal = true)
  961. {
  962.   _ASSERTE(IsBound());
  963.  
  964.   VARIANT* retVal = 0;
  965.  
  966.   // Having return value implies an Args array (even if it contains only one
  967.   // variant for the return value).
  968.   //
  969.   _ASSERTE((hasRetVal==false && args==0) || 
  970.            (hasRetVal==false && args!=0) ||
  971.            (hasRetVal==true  && args!=0));
  972.  
  973.   // Setup return VARIANT 
  974.   // NOTE: PROPERTYPUTs do not return a result
  975.   //
  976.   if (!(dFlags & (dfPropPut|dfPropPutRef)) && hasRetVal)
  977.     retVal = args->GetRetVal();
  978.  
  979.   // Special DispId for Property Puts
  980.   //
  981.   static DISPID DispIdPropertyPut = DISPID_PROPERTYPUT;
  982.  
  983.   // Setup DISPATCH parameters
  984.   //
  985.   DISPPARAMS params;
  986.   ::ZeroMemory(¶ms, sizeof(params));
  987.  
  988.   // Set parameters (Note: PropPut[Ref] expected to have Count)
  989.   if (args && args->GetCount())
  990.   {
  991.     params.cArgs = args->GetCount();
  992.     params.rgvarg= args->GetArgs();
  993.  
  994.     // Handle PROPERTYPUT
  995.     // NOTE: Assumes no named-arguments params have been setup
  996.     //
  997.     if (dFlags & (dfPropPut|dfPropPutRef))
  998.     {
  999.       params.cNamedArgs = 1;
  1000.       params.rgdispidNamedArgs = &DispIdPropertyPut;
  1001.     }
  1002.   }
  1003.  
  1004.   // Reset Error Information
  1005.   m_ErrArg = 0;
  1006.   ::ZeroMemory(&m_ExcepInfo, sizeof(m_ExcepInfo));
  1007.  
  1008.   // Invoke
  1009.   HRESULT hr = m_Dispatch->Invoke(dispid, IID_NULL, m_lcid, WORD(dFlags), ¶ms,
  1010.                                   retVal, &m_ExcepInfo, &m_ErrArg);
  1011.   // Output a little trace
  1012.   OLETRACE("Inv(%d) %s, 0x%lX, retVT(0x%X), ErrArg(%d)\n",
  1013.            dispid, SUCCEEDED(hr) ? "OK" : "FL", LONG(hr), 
  1014.            retVal ? retVal->vt : VT_NULL, m_ErrArg);
  1015.   // Return result
  1016.   return hr;                                                                              
  1017. }
  1018.  
  1019.  
  1020. // Property Get that returns a Variant
  1021. //
  1022. template <class DISPINTF> VARIANTOBJ
  1023. TAutoDriver<DISPINTF>::OlePropertyGet(DISPID dispid)
  1024. {
  1025.   TAutoArgs<0> args;
  1026.   OlePropertyGet(dispid, args);
  1027.   return args.GetRetVariant();
  1028. }
  1029.  
  1030. // TDispIdBase - Base class used by TDispId; allows us to have only one copy of the
  1031. //               flag governing whether DISPID should be looked up
  1032. template <class T>
  1033. class TDispIdBase
  1034. {
  1035. public:
  1036.   static  bool m_AlwaysGetDispid;
  1037. };
  1038.  
  1039. // This flag triggers a lookup even if the object was pass a valid dispid!
  1040. //
  1041. template <class T>
  1042. bool TDispIdBase<T>::m_AlwaysGetDispid = false;
  1043.  
  1044. // TDispId - Class used to retrieve and cache a DISPID
  1045. //
  1046. template<class DISPINTF = IDispatch>
  1047. class TDispId : public TDispIdBase<IDispatch>
  1048. {
  1049. public:
  1050.   TDispId(TAutoDriver<DISPINTF>& dispatch, LPCWSTR pName, DISPID id= DISPID_UNKNOWN) : m_DispId(id), 
  1051.                                                                                        m_HResult(S_OK)
  1052.   {
  1053.  
  1054.     if (id == DISPID_UNKNOWN || m_AlwaysGetDispid)
  1055.       m_HResult = GetID(dispatch, pName);
  1056.     _ASSERTE_(SUCCEEDED(m_HResult));  
  1057.   }
  1058.  
  1059.   TDispId(DISPID id) : m_DispId(id), m_HResult(S_OK)
  1060.   {}
  1061.  
  1062.   HRESULT GetID(TAutoDriver<DISPINTF>& dispatch, LPCWSTR pName)
  1063.   {
  1064.     return dispatch.GetIDsOfNames(pName, m_DispId);
  1065.   }
  1066.  
  1067.   operator DISPID() const
  1068.   {
  1069.     return  m_DispId;
  1070.   }
  1071.  
  1072.   HRESULT GetResult() const
  1073.   {
  1074.     return m_HResult;
  1075.   }
  1076.  
  1077.  
  1078. protected:
  1079.   DISPID    m_DispId;
  1080.   HRESULT   m_HResult;
  1081. };
  1082.  
  1083. #endif    //  UTILCLS_NO_AUTOMATION
  1084.  
  1085. #endif  __UTILCLS_H
  1086.  
  1087.  
  1088.